TOOL.Category    = "Conna's Tools"
TOOL.Name        = "#Toggleable Hoverball Tool"
TOOL.Command     = nil
TOOL.ConfigName  = ""

TOOL.ClientConVar["KeyUP"] = "9"
TOOL.ClientConVar["KeyDN"] = "6"
TOOL.ClientConVar["Toggle"] = "5"
TOOL.ClientConVar["Speed"] = "1"
TOOL.ClientConVar["Resistance"] = "0"
TOOL.ClientConVar["Strength"] = "1"
TOOL.ClientConVar["Stop"] = "0"

// Register

cleanup.Register("toggleablehoverballs")

// Console

CreateConVar("sbox_maxtoggleablehoverballs", 10, FCVAR_NOTIFY)

// Client

if (CLIENT) then
	// Tool
	
	language.Add("Tool_toggleablehoverballs_name", "Toggleable Hoverball Tool")
	language.Add("Tool_toggleablehoverballs_desc", "Toggleable Hoverballs which press key when weight is applied")
	language.Add("Tool_toggleablehoverballs_0", "Left click to spawn a Toggleable Hoverball")
	
	// Other
	
	language.Add("Undone_toggleablehoverballs", "Undone Toggleable Hoverball")
	language.Add("SBoxLimit_toggleablehoverballs", "You've hit the Toggleable Hoverballs limit!")
	language.Add("Cleanup_toggleablehoverballs", "Toggleable Hoverballs")
	language.Add("Cleaned_toggleablehoverballs", "Cleaned up all Toggleable Hoverballs")
end

// Message

function TOOL:Message(Text)
	if SERVER then
		self:GetOwner():SendLua("GAMEMODE:AddNotify('"..Text.."', NOTIFY_GENERIC, 10)")
		self:GetOwner():SendLua("surface.PlaySound('ambient/water/drip"..math.random(1, 4)..".wav')")
	end
end

// Left click

function TOOL:LeftClick(Trace)
	if(CLIENT) then
		return true
	end
	
	// Locals
	
	local Player = self:GetOwner()

	local KeyUP = self:GetClientNumber("KeyUP")
	local KeyDN = self:GetClientNumber("KeyDN")
	local Toggle = self:GetClientNumber("Toggle")
	local Speed = self:GetClientNumber("Speed")
	local Resistance = self:GetClientNumber("Resistance")
	local Strength = self:GetClientNumber("Strength")
	local Stop = self:GetClientNumber("Stop")
	
	// Keep it nice and whole
	
	Resistance = math.Clamp(Resistance, 0, 20)
	Strength   = math.Clamp(Strength, 0.1, 20)
	
	if (Trace.Entity and Trace.Entity:IsValid() and Trace.Entity:GetClass() == "gmod_toggleablehoverball") then
		// Merge
		
		local Table = {
			Speed = Speed,
			Strength = Strength,
			Stop     = Stop,
			Resistance = Resistance
		}
		
		table.Merge(Trace.Entity:GetTable(), Table)
		
		// Other
		
		Trace.Entity:GetTable():SetSpeed(Speed)
		Trace.Entity:GetTable():SetAirResistance(Resistance)
		Trace.Entity:GetTable():SetStrength(Strength)
		
		self:Message("Properties changed for Toggleable Hoverball!")
		
		return true
	end

	local Ball = CreateToggleableHoverball(Player, Trace.HitPos, KeyUP, KeyDN, Toggle, Speed, Stop, Resistance, Strength)
	
	if not (Ball) then return false end
	
	local Constraint
	
	// Don't weld to world
	
	if (Trace.Entity != NULL && !Trace.Entity:IsWorld()) then
		Constraint = constraint.Weld(Trace.Entity, Ball, Trace.PhysicsBone, 0, 0, true)
		
		Trace.Entity:DeleteOnRemove(Ball)
		
		Ball:GetPhysicsObject():EnableCollisions(false)
		Ball:GetTable().nocollide = true
	end
	
	undo.Create("toggleablehoverballs")
		undo.AddEntity(Ball)
		undo.AddEntity(Constraint)
		undo.SetPlayer(Player)
	undo.Finish()
	
	Player:AddCount("toggleablehoverballs", Ball)
	Player:AddCleanup("toggleablehoverballs", Ball)
	Player:AddCleanup("toggleablehoverballs", Constraint)
	
	self:Message("Toggleable Hoverball created!")
	
	return true, Ball
end

// Right click

function TOOL:RightClick(Trace)
	return self:LeftClick(Trace)
end

// Make it

if (SERVER) then
	function CreateToggleableHoverball(Player, Pos, KeyUP, KeyDN, Toggle, Speed, Stop, Resistance, Strength, Vel, Avel, Frozen, Nocollide)
		if (!Player:CheckLimit("toggleablehoverballs")) then return false end
		
		local Ball = ents.Create("gmod_toggleablehoverball")
		
		// Spawn it
		
		Ball:SetPos(Pos)
		Ball:Spawn()
		
		// Stuff
		
		Ball:GetTable():SetSpeed(Speed)
		Ball:GetTable():SetPlayer(Player)
		Ball:GetTable():SetAirResistance(Resistance)
		Ball:GetTable():SetStrength(Strength)
		
		// Nocollide and frozen
		
		if (Frozen) then Ball:GetPhysicsObject():EnableMotion(false) end
		
		if (Nocollide) then Ball:GetPhysicsObject():EnableCollisions(false) end
		
		// Keypad
		
		numpad.OnDown(Player, KeyUP, "Hoverball.Activate", Ball, true)
		numpad.OnUp(Player, KeyUP, "Hoverball.Activate", Ball, false)

		numpad.OnDown(Player, KeyDN, "Hoverball.Deactivate", Ball, true)
		numpad.OnUp(Player, KeyDN, "Hoverball.Deactivate", Ball, false)
		
		numpad.OnDown(Player, Toggle, "Hoverball.Toggle", Ball, true)
		numpad.OnUp(Player, Toggle, "Hoverball.Toggle", Ball, false)
		
		// Merge
		
		local Table = {
			KeyUP = KeyUP,
			KeyDN = KeyDN,
			Nocollide = Nocollide,
			Speed = Speed,
			Stop  = Stop,
			Strength = Strength,
			Resistance = Resistance
		}
		
		table.Merge(Ball:GetTable(), Table)
		
		return Ball
	end
	
	duplicator.RegisterEntityClass("gmod_toggleablehoverball", CreateToggleableHoverball, "Pos", "KeyUP", "KeyDN", "Toggle", "Speed", "Stop", "Resistance", "Strength", "Vel", "Avel", "Frozen", "Nocollide")
end

// Control panel

function TOOL.BuildCPanel(Panel)
	Panel:AddControl("Header", {Text = "#Tool_toggleablehoverballs_name", Description = "#Tool_toggleablehoverballs_desc"})
	
	Panel:AddControl("Numpad", {Label = "Keypad Raise", Command = "toggleablehoverballs_KeyUP", Label2 = "Keypad Lower", Command2 = "toggleablehoverballs_KeyDN", ButtonSize = 22})
	
	Panel:AddControl("Numpad", {Label = "Keypad Toggle", Command = "toggleablehoverballs_Toggle", ButtonSize = 22})
	
	Panel:AddControl("Slider", {Label = "Movement Speed", Type = "Integer", Min = 0, Max = 10, Command = "toggleablehoverballs_Speed"})
	
	Panel:AddControl("Slider", {Label = "Strength", Type = "Integer", Min = 0.1, Max = 10, Command = "toggleablehoverballs_Strength"})
	
	Panel:AddControl("Slider", {Label = "Air Resistance", Type = "Integer", Min = 0, Max = 10, Command = "toggleablehoverballs_Resistance"})

	Panel:AddControl("CheckBox", {Label = "Stop instantly when re-activated", Command = "toggleablehoverballs_Stop"})
end

// Ghost

function TOOL:UpdateGhostToggleableHoverball(Entity, Player)
	if (!Entity) then return end
	
	if (!Entity:IsValid()) then return end

	local TR = utilx.GetPlayerTrace(Player, Player:GetCursorAimVector())
	
	local Trace = util.TraceLine(TR)
	
	if (!Trace.Hit) then return end
	
	if (Trace.Entity && Trace.Entity:GetClass() == "gmod_toggleablehoverball" || Trace.Entity:IsPlayer()) then
		Entity:SetNoDraw(true)
		
		return
	end
	
	Entity:SetPos(Trace.HitPos)
	
	Entity:SetNoDraw(false)
end

// Think

function TOOL:Think()
	if (self:GetOwner() and self:GetOwner():IsPlayer()) then
		if (!self.GhostEntity || !self.GhostEntity:IsValid() || self.GhostEntity:GetModel() != "models/dav0r/hoverball.mdl") then
			self:MakeGhostEntity("models/dav0r/hoverball.mdl", Vector(0, 0, 0), Angle(0, 0, 0) )
		end
		
		self:UpdateGhostToggleableHoverball(self.GhostEntity, self:GetOwner())
	end
end